#pragma once
#include <iostream>
#include <unordered_map>
#include <functional>
#include <string>
#include "Util.hpp"
#include "Sock.hpp"
#include "Epoller.hpp"
#include "Protocol.hpp"
#include "blockqueue/blockqueue.hpp"
#include "threadPool/GardLock.hpp"

struct Connection;
class EpollServer;

const static int gbuff = 1024;
const static uint16_t default_port = 8888;
using callback_t = std::function<void(Connection *)>;
using func_t = std::function<protocol_ns::Response(const protocol_ns::Request&)>;

enum IFLISTEN
{
    ISLISTEN,
    NONELISTEN
};

struct Connection
{
    Connection(int fd, int event)
        : _fd(fd), _event(event)
    {
    }

    void Register(callback_t recver, callback_t sender, callback_t excepter)
    {
        _recver = recver;
        _sender = sender;
        _excepter = excepter;
    }

    int _fd;
    uint32_t _event;
    std::string _inbuffer;
    std::string _outbuffer;

    callback_t _recver;
    callback_t _sender;
    callback_t _excepter;

    EpollServer *R;
};

class EpollServer
{
    const static int num = 64;
public:
    EpollServer(func_t func, blockqueue<int>* bq, IFLISTEN LISTEN, uint16_t port = default_port)
        : _port(port), _func(func), _LISTEN(LISTEN), _bq(bq)
    {
        pthread_mutex_init(&mutex, nullptr);
    }

    void InitServer()
    {
        _epoll.Create();
        // 判断该句柄是否是主句柄，是则需要创建套接字
        if(_LISTEN == ISLISTEN)
        {
            _listensock.Socket();
            _listensock.Bind(_port);
            _listensock.Listen();
            AddConnection(_listensock.GetFd(), EPOLLIN | EPOLLET);
        }

        LogMessage(Info, "InitServer success...");
    }

    void Start()
    {
        int timeout = 0;
        while (true)
        {
            LoopOnce(timeout);
            if(_LISTEN == NONELISTEN && !_bq->isEmpty()) // 如果队列有东西则取出来加入到EOPLL中
            {
                GardLock gl(&mutex);
                if(_bq->isEmpty())
                {
                    LogMessage(Info, "Get fail...");
                    continue; // 保证竞争失败的线程，不会被内部的消息队列挂起
                }
                int outfd = 0; 
                _bq->pop(&outfd);
                AddConnection(outfd, EPOLLIN | EPOLLET);
                LogMessage(Info, "Get new fd", outfd);
            }
        }
    }

    void EnableReadWrite(Connection *conn, bool isRead, bool isWrite)
    {
        uint32_t event = EPOLLET;
        event |= (isRead == true ? EPOLLIN: 0);
        event |= (isWrite == true ? EPOLLOUT: 0);
        _epoll.CtlEvent(conn->_fd, event, EPOLL_CTL_MOD);
    }

    ~EpollServer()
    {
        for(auto [fd, conn] : _connections)
        {
            delete conn;
        }
        pthread_mutex_destroy(&mutex);
    }

private:
    void LoopOnce(int timeout)
    {
        int n = _epoll.Wait(events, num, timeout);
        for(int i = 0; i < n; i++)
        {
            int fd = events[i].data.fd;
            uint32_t event = events[i].events;
            // 将异常情况统一交由Recver和Sender来处理
            if((event & EPOLLERR) || (event & EPOLLHUP))
                event |= (EPOLLIN | EPOLLOUT);

            if((event & EPOLLIN) && (IsConnExist(fd)))
                _connections[fd]->_recver(_connections[fd]);
            if((event & EPOLLOUT) && (IsConnExist(fd)))
                _connections[fd]->_sender(_connections[fd]);
        }
    }
    // connection对象处理统一化解决方案
    void Accepter(Connection *conn)
    {
        do
        {
            int error;
            uint16_t client_port;
            std::string client_ip;
            int sock = _listensock.Accept(&client_ip, &client_port, &error);

            if(sock > 0)
            {
                _bq->push(sock);
                LogMessage(Info, "Accept, [%s:%d]", client_ip.c_str(), client_port);
            }
            else
            {
                if((error == EAGAIN) || (error == EWOULDBLOCK)) // 已读取完本次数据
                    break;
                else if(error == EINTR) // 读取过程被信号所中断
                    continue;
                else // 读取错误
                {
                    LogMessage(Warring, "Accepter fail, %d, %s", error, strerror(error));
                    continue;
                }
            }
        } while (conn->_event & EPOLLET);
    }

    void Recver(Connection *conn)
    {
        if(!ReceverHelper(conn)) return;

        HandlerRequest(conn);
        // 一般我们在面对写入的时候，直接写入，没写完，才交给epoll
        if(!conn->_outbuffer.empty())
            conn->_sender(conn);
    }
    // 提取完整报文的处理流程
    void Sender(Connection *conn)
    {
        bool safe = true;
        do
        {
            ssize_t n = send(conn->_fd, conn->_outbuffer.c_str(), conn->_outbuffer.size(), 0);
            if(n > 0)
            {
                conn->_outbuffer.erase(0, n);
            }
            else 
            {
                if((errno == EAGAIN) || (errno == EWOULDBLOCK)) 
                    break;
                else if(errno == EINTR) 
                    continue;
                else 
                {
                    LogMessage(Warring, "Sender fail, %d, %s", errno, strerror(errno));
                    conn->_excepter(conn);
                    safe = false;
                    break;
                }
            }
        } while (conn->_event & EPOLLET);

        if(!safe) return;
        if(conn->_outbuffer.empty())
            EnableReadWrite(conn, true, false);
        else
            EnableReadWrite(conn, true, true);
    }

    void Excepter(Connection *conn)
    {
        _epoll.DelEvent(conn->_fd);
        _connections.erase(conn->_fd);
        close(conn->_fd);
        LogMessage(Info, "Excepter done, fd: %d...", conn->_fd);
        delete conn;
    }

    void AddConnection(int fd, uint32_t event)
    {
        if(event & EPOLLET) Util::SetNonBlock(fd);
        Connection *conn = new Connection(fd, event);
        if (conn->_fd == _listensock.GetFd())
        {
            conn->Register(std::bind(&EpollServer::Accepter, this, std::placeholders::_1), nullptr, nullptr);
        }
        else
        {
            conn->Register(std::bind(&EpollServer::Recver, this, std::placeholders::_1)
                            , std::bind(&EpollServer::Sender, this, std::placeholders::_1)
                            , std::bind(&EpollServer::Excepter, this, std::placeholders::_1));
        }
        conn->_event = event;
        conn->R = this;
        _epoll.CtlEvent(fd, event, EPOLL_CTL_ADD);
        _connections[conn->_fd] = conn; 
    }

    bool IsConnExist(int fd)
    {
        return _connections.count(fd) > 0;
    }
    // V3
    void HandlerRequest(Connection *conn)
    {
        bool quit = false;
        while(!quit)
        {
            std::string reqStr;
            int n = protocol_ns::ReadPackage(conn->_inbuffer, &reqStr);
            if(n > 0)
            {
                reqStr = protocol_ns::RemoveHeader(reqStr, n);
                protocol_ns::Request req;
                req.Deserialize(reqStr);

                protocol_ns::Response resp = _func(req);
                std::string respStr;
                resp.Serialize(&respStr);
                respStr = protocol_ns::AddHeader(respStr);

                conn->_outbuffer += respStr;
            }
            else
                quit = true;
        }
    }

    bool ReceverHelper(Connection *conn)
    {
        bool safe = true;
        do
        {
            char buffer[gbuff];
            ssize_t n = recv(conn->_fd, buffer, gbuff, 0);

            if(n > 0)
            {
                buffer[n] = 0;
                conn->_inbuffer += buffer;
            }
            else if(n == 0) // 链接断开
            {
                conn->_excepter(conn);
                safe = false;
                break;
            }
            else
            {
                if((errno == EAGAIN) || (errno == EWOULDBLOCK)) 
                    break;
                else if(errno == EINTR) 
                    continue;
                else 
                {
                    LogMessage(Warring, "Recver fail, %d, %s", errno, strerror(errno));
                    conn->_excepter(conn);
                    safe = false;
                    break;
                }
            }
        } while (conn->_event & EPOLLET);
        return safe;
    }
private:
    IFLISTEN _LISTEN;
    Sock _listensock;
    uint16_t _port;
    Epoller _epoll;
    func_t _func;
    blockqueue<int>* _bq;
    pthread_mutex_t mutex;
    struct epoll_event events[num]; // 用于接收返回值？？
    std::unordered_map<int, Connection *> _connections;
};